
from classfier.BaseModel import BaseModelUtil

from sklearn.linear_model import LogisticRegression



class LogisticUtil(BaseModelUtil):
    def __init__(self, dp, X, model_random_state,split_random_state, save_path,data_type):
        super().__init__(dp, X, model_random_state=model_random_state,split_random_state=split_random_state,save_path=save_path, model_name='Logistic',data_type=data_type)
        self.run()

    def build_model(self,**kwargs):
        return LogisticRegression(random_state=self.model_random_state,solver='liblinear',class_weight='balanced', **kwargs)

    def get_param_grid(self):
        param_grid = [
            {'penalty': ['l1'], 'C': [0.01, 0.1, 1], 'solver': ['liblinear', 'saga'], 'max_iter': [200]},
            {'penalty': ['l2'], 'C': [0.01, 0.1, 1], 'solver': ['liblinear', 'lbfgs', 'sag', 'saga'],
             'max_iter': [200]},
            {'penalty': ['elasticnet'], 'C': [0.01, 0.1, 1], 'solver': ['saga'], 'l1_ratio': [0.2, 0.5, 0.8],
             'max_iter': [200]},
            {'penalty': [None], 'solver': ['lbfgs', 'sag', 'newton-cg'], 'max_iter': [200]}
        ]
        return param_grid

from sklearn.svm import SVC
class SVMUtil(BaseModelUtil):
    def __init__(self, dp, X, model_random_state,split_random_state, save_path,data_type):
        super().__init__(dp, X, model_random_state=model_random_state,split_random_state=split_random_state,save_path=save_path, model_name='SVM',data_type=data_type)
        self.run()

    def build_model(self,**kwargs):
        return SVC(random_state=self.model_random_state,probability=True, **kwargs)

    def get_param_grid(self):
        param_grid = {
            'C': [0.1, 1, 10, 100],  # 惩罚系数，越大表示对错误分类惩罚越重
            'kernel': ['linear', 'rbf', 'poly', 'sigmoid'],  # 核函数
            'gamma': ['scale', 'auto', 0.01, 0.1, 1],  # rbf/poly/sigmoid 核的 gamma 参数
            'degree': [2, 3, 4],  # 仅对 kernel='poly' 有效
            'coef0': [0.0, 0.1, 0.5],  # poly/sigmoid 核函数的独立项
            'shrinking': [True, False],  # 是否使用shrinking启发式（通常True更好）
            'probability': [True],  # 若需预测概率则必须设为True（默认False）
        }
        return param_grid

#  Gradient Boosting
from sklearn.ensemble import GradientBoostingClassifier
class GBMUtil(BaseModelUtil):
    def __init__(self, dp, X, model_random_state,split_random_state, save_path,data_type):
        super().__init__(dp, X, model_random_state=model_random_state,split_random_state=split_random_state,save_path=save_path, model_name='GBM',data_type=data_type)
        self.run()

    def build_model(self, **kwargs):
        return GradientBoostingClassifier(random_state=self.model_random_state, **kwargs)

    def get_param_grid(self):
        param_grid = {
            'n_estimators': [100, 200, 300],  # 弱分类器数量（即树的数量）
            'learning_rate': [0.01, 0.05, 0.1, 0.2],  # 学习率，控制每棵树对最终结果的影响
            'max_depth': [3, 4, 5, 6],  # 决策树的最大深度
            'min_samples_split': [2, 5, 10],  # 内部分裂所需的最小样本数
            'min_samples_leaf': [1, 2, 4],  # 叶子节点所需的最小样本数
            'max_features': ['sqrt', 'log2', None],  # 每棵树考虑的最大特征数
            'subsample': [0.6, 0.8, 1.0],  # 每棵树训练时使用的样本比例（<1时是随机抽样）
        }
        return param_grid

#  Neural Network
from sklearn.neural_network import MLPClassifier
class NNUtil(BaseModelUtil):
    def __init__(self, dp, X, model_random_state, split_random_state, save_path, data_type):
        super().__init__(dp, X, model_random_state=model_random_state, split_random_state=split_random_state,
                         save_path=save_path, model_name='NeuralNet', data_type=data_type)
        self.run()

    def build_model(self, **kwargs):
        return MLPClassifier(random_state=self.model_random_state,early_stopping=True, **kwargs)

    def get_param_grid(self):
        param_grid = {
            'hidden_layer_sizes': [(50,), (100,), (100, 50), (50, 50, 50)],  # 网络结构：每层神经元数
            'activation': ['relu', 'tanh', 'logistic'],  # 激活函数
            'solver': ['adam', 'sgd', 'lbfgs'],  # 权重优化算法
            'alpha': [1e-5, 1e-4, 1e-3, 1e-2],  # L2正则化参数（防过拟合）
            'learning_rate': ['constant', 'adaptive'],  # 学习率调节策略
            'learning_rate_init': [0.001, 0.01, 0.1],  # 初始学习率
            'max_iter': [200, 500],  # 最大迭代次数
            'early_stopping': [True],  # 提前停止以防过拟合
        }
        return param_grid


# Random Forest
from sklearn.ensemble import RandomForestClassifier
class RFUtil(BaseModelUtil):
    def __init__(self, dp, X, model_random_state, split_random_state, save_path, data_type):
        super().__init__(dp, X, model_random_state=model_random_state, split_random_state=split_random_state,
                         save_path=save_path, model_name='RF', data_type=data_type)
        self.run()

    def build_model(self, **kwargs):
        return RandomForestClassifier(random_state=self.model_random_state, **kwargs)

    def get_param_grid(self):
        param_grid = {
            'n_estimators': [100, 200, 500],  # 森林中树的数量
            'max_depth': [None, 10, 20, 30],  # 每棵树最大深度，None 表示不限制
            'min_samples_split': [2, 5, 10],  # 内部节点再划分所需最小样本数
            'min_samples_leaf': [1, 2, 4],  # 叶节点所需最小样本数
            'max_features': ['sqrt', 'log2', None],  # 每棵树分裂时考虑的最大特征数
            'bootstrap': [True, False],  # 是否采用有放回抽样
            'class_weight': [None, 'balanced'],  # 是否自动调整类别权重
            'random_state': [42]  # 固定随机种子，确保可复现
        }
        return param_grid


# XGBoost
from xgboost import XGBClassifier
class XGBoostUtil(BaseModelUtil):
    def __init__(self, dp, X, model_random_state, split_random_state, save_path, data_type):
        super().__init__(dp, X, model_random_state=model_random_state, split_random_state=split_random_state,
                         save_path=save_path, model_name='XGBoost', data_type=data_type)
        self.run()

    def build_model(self, **kwargs):
        return XGBClassifier(random_state=self.model_random_state, **kwargs)

    def get_param_grid(self):
        param_grid = {
            'n_estimators': [100, 200, 300],  # 树的数量
            'learning_rate': [0.01, 0.05, 0.1, 0.2],  # 学习率
            'max_depth': [3, 5, 7, 10],  # 每棵树的最大深度
            'min_child_weight': [1, 3, 5],  # 决定叶子节点最小样本权重和
            'subsample': [0.6, 0.8, 1.0],  # 每棵树训练用的样本比例
            'colsample_bytree': [0.6, 0.8, 1.0],  # 每棵树使用的特征比例
            'gamma': [0, 0.1, 0.3, 0.5],  # 信息增益的最小值，越大越保守
            'reg_alpha': [0, 0.01, 0.1],  # L1 正则
            'reg_lambda': [1, 1.5, 2],  # L2 正则
            'scale_pos_weight': [1],  # 类别不平衡时可设为正负样本比例
            'random_state': [42],  # 固定随机种子以复现结果
            'use_label_encoder': [False],  # 避免警告，建议始终设置为 False
            'eval_metric': ['logloss']  # 配合 use_label_encoder=False 使用
        }
        return param_grid


# K-Nearest Neighbors
from sklearn.neighbors import KNeighborsClassifier
class KNNUtil(BaseModelUtil):
    def __init__(self, dp, X, model_random_state, split_random_state, save_path, data_type):
        super().__init__(dp, X, model_random_state=model_random_state, split_random_state=split_random_state,
                         save_path=save_path, model_name='KNN', data_type=data_type)
        self.run()

    def build_model(self, **kwargs):
        return KNeighborsClassifier( **kwargs)

    def get_param_grid(self):
        param_grid = {
            'n_neighbors': [3, 5, 7, 9, 11],  # 考虑的邻居个数（k 值）
            'weights': ['uniform', 'distance'],  # 所有邻居等权 or 距离加权
            'metric': ['minkowski', 'euclidean', 'manhattan'],  # 距离度量方式
            'p': [1, 2],  # 当 metric='minkowski' 时：p=1 为曼哈顿距离，p=2 为欧氏距离
            'leaf_size': [20, 30, 40],  # 构建树时的叶子节点大小（影响速度）
            'algorithm': ['auto', 'ball_tree', 'kd_tree', 'brute']  # 最近邻搜索算法
        }
        return param_grid


# AdaBoost
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import AdaBoostClassifier
class AdaBoostUtil(BaseModelUtil):
    def __init__(self, dp, X, model_random_state, split_random_state, save_path, data_type):
        super().__init__(dp, X, model_random_state=model_random_state, split_random_state=split_random_state,
                         save_path=save_path, model_name='AdaBoost', data_type=data_type)
        self.run()

    def build_model(self, **kwargs):
        return AdaBoostClassifier(random_state=self.model_random_state, **kwargs)

    def get_param_grid(self):
        param_grid = {
            'n_estimators': [50, 100, 200],  # 弱分类器数量（迭代次数）
            'learning_rate': [0.01, 0.1, 0.5, 1.0],  # 每个弱分类器的权重缩放系数
            'base_estimator': [
                DecisionTreeClassifier(max_depth=1),
                DecisionTreeClassifier(max_depth=2),
                DecisionTreeClassifier(max_depth=3)
            ],  # 基学习器（默认是 stump，即 max_depth=1 的树）
            'algorithm': ['SAMME', 'SAMME.R'],  # 提升算法：SAMME.R 更常用（连续输出支持）
            'random_state': [42]  # 控制随机性，确保结果可复现
        }
        return param_grid



# CatBoost
from catboost import CatBoostClassifier
class CatBoostUtil(BaseModelUtil):
    def __init__(self, dp, X, model_random_state, split_random_state, save_path, data_type):
        super().__init__(dp, X, model_random_state=model_random_state, split_random_state=split_random_state,
                         save_path=save_path, model_name='CatBoost', data_type=data_type)
        self.run()

    def build_model(self, **kwargs):
        return CatBoostClassifier(random_state=self.model_random_state,verbose=0, **kwargs)

    def get_param_grid(self):
        param_grid = {
            'iterations': [100, 200, 500],  # 总迭代次数（树的数量）
            'learning_rate': [0.01, 0.05, 0.1],  # 学习率
            'depth': [4, 6, 8, 10],  # 每棵树的最大深度
            'l2_leaf_reg': [1, 3, 5],  # L2 正则化系数
            'border_count': [32, 64, 128],  # 连续特征分箱数（常用于分类）
            'bagging_temperature': [0, 1, 5],  # Bagging 强度（0 表示关闭）
            'random_strength': [1, 5, 10],  # 用于特征选择的随机性强度
            'verbose': [0],  # 关闭日志输出
        }
        return param_grid